/*
 * Copyright 2010 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.websocket;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Maintains a connected pair of piped streams.
 */
class PipedStreamPair {

  private final BlockingQueue<byte[]> pipeBuffer = new LinkedBlockingQueue<byte[]>();

  private Thread readThread = new Thread("Pipe reader") {

    private final byte[] buf = new byte[8192];

    @Override
    public void run() {
      int n;
      try {
        while ((n = copyInput.read(buf)) >= 0) {
          if (n == 0) {
            continue;
          }
          byte[] bufCopy = new byte[n];
          System.arraycopy(buf, 0, bufCopy, 0, n);
          pipeBuffer.add(bufCopy);
        }
      } catch (IOException e) {
      }
      pipeBuffer.add(new byte[0]);
    }
  };

  private Thread writeThread = new Thread("Pipe writer") {

    @Override
    public void run() {
      while (true) {
        byte[] buf = null;
        try {
          buf = pipeBuffer.take();
        } catch (InterruptedException e1) {
          break;
        }
        if (buf == null || buf.length == 0) {
          break;
        }
        try {
          copyOutput.write(buf);
        } catch (IOException e) {
          break;
        }
      }
      try {
        copyOutput.close();
      } catch (IOException e) {
      }
    }
  };

  private final PipedOutputStream output;
  private final PipedInputStream input;

  private final PipedOutputStream copyOutput;
  private final PipedInputStream copyInput;

  public PipedStreamPair() {
    PipedOutputStream out = null;
    PipedInputStream in = null;
    try {
      out = new PipedOutputStream();
      in = new PipedInputStream(out);
    } catch (IOException e) {        
    }
    copyOutput = out;
    input = in;
    try {
      out = new PipedOutputStream();
      in = new PipedInputStream(out);
    } catch (IOException e) {        
    }
    output = out;
    copyInput = in;
    writeThread.start();
    readThread.start();
  }
  
  public PipedInputStream getInputStream() {
    return input;
  }
  
  public PipedOutputStream getOutputStream() {
    return output;
  }
}